package com.dhcc.bpm.modules.api.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dhcc.bpm.common.annotation.Log;
import com.dhcc.bpm.common.config.AppEmailConfig;
import com.dhcc.bpm.common.constant.FilePathConstant;
import com.dhcc.bpm.common.enums.BusinessType;
import com.dhcc.bpm.common.enums.ConfigType;
import com.dhcc.bpm.common.json.JSONObject;
import com.dhcc.bpm.common.redisMessage.RedisMessageSender;
import com.dhcc.bpm.common.utils.DateUtils;
import com.dhcc.bpm.common.utils.EmailUtils;
import com.dhcc.bpm.common.utils.ExcelUtil;
import com.dhcc.bpm.common.utils.FormatUtils;
import com.dhcc.bpm.modules.api.entity.Product;
import com.dhcc.bpm.modules.api.entity.ProductApi;
import com.dhcc.bpm.modules.api.entity.Sys;
import com.dhcc.bpm.modules.api.service.IApiService;
import com.dhcc.bpm.modules.api.service.IProductApiService;
import com.dhcc.bpm.modules.api.service.IProductService;
import com.dhcc.bpm.modules.api.service.ISysService;
import com.dhcc.bpm.modules.api.vo.ApiVO;
import com.dhcc.bpm.modules.api.vo.OpcAppApiVo;
import com.dhcc.bpm.modules.api.vo.ProductVO;
import com.dhcc.bpm.modules.api.vo.productListVo;
import com.dhcc.bpm.modules.common.entity.Plupload;
import com.dhcc.bpm.modules.common.entity.Upload;
import com.dhcc.bpm.modules.common.service.IPluploadService;
import com.dhcc.bpm.modules.content.entity.DocDirectory;
import com.dhcc.bpm.modules.content.service.IDocDirectoryService;
import com.dhcc.bpm.modules.cost.service.ICostRuleService;
import com.dhcc.bpm.modules.cost.vo.CostRuleVO;
import com.dhcc.bpm.modules.log.service.IGatewayLogDayService;
import com.dhcc.bpm.modules.log.vo.AppApiViewVo;
import com.dhcc.bpm.modules.orga.entity.App;
import com.dhcc.bpm.modules.orga.entity.AppApi;
import com.dhcc.bpm.modules.orga.service.IAppApiService;
import com.dhcc.bpm.modules.orga.service.IAppService;
import com.dhcc.bpm.modules.system.entity.Role;
import com.dhcc.bpm.modules.system.service.IRoleService;
import com.dhcc.bpm.modules.system.service.ISerialNumberService;
import com.dhcc.bpm.modules.workflow.dto.ApiBO;
import com.dhcc.bpm.modules.workflow.dto.ProcessStartDto;
import com.dhcc.bpm.modules.workflow.dto.TaskCommitDto;
import com.dhcc.bpm.modules.workflow.dto.TaskDto;
import com.dhcc.bpm.modules.workflow.service.IWorkFlowService;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;

/**
 * @ClassName ProductController
 * @Description 产品表 控制器
 * @Author daina
 * @Date 2020/2/25 13:14
 * @Version V1.0
 * @Copyright: 2020 东华软件 . All rights reserved.
 */
@RestController
@AllArgsConstructor
@NoArgsConstructor
@RequestMapping("bpm-api/product")
@Api(value = "产品表", tags = "产品表接口")
public class ProductController extends BladeController {
    private static final Logger log = LoggerFactory.getLogger(ProductController.class);
    @Autowired
    private IDocDirectoryService docDirectoryService;
    @Autowired
    private IProductService productService;
    @Autowired
    private IAppService appService;
    @Autowired
    private RedisMessageSender redisMessageSender;
    @Autowired
    private IProductApiService productApiService;
    @Autowired
    private AppEmailConfig appEmailConfig;
    @Autowired
    private ISerialNumberService serialNumberService;
    @Autowired
    private IAppApiService appApiService;
    @Autowired
    private EmailUtils emailUtils;
    @Autowired
    private IApiService apiService;
    @Autowired
    private IPluploadService pluploadService;
    @Autowired
    private ICostRuleService costRuleService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private IWorkFlowService iWorkFlowService;

    @Autowired
    private IGatewayLogDayService gatewayLogDayService;
    @Autowired
    private IRoleService roleService;
    @Autowired
    private ISysService sysService;

    @Value("${bpm.approval.isSendMail}")
    private boolean isSendFlag;
    private String path;

    @Value("${bpm.file-public-path}")
    public void setFileUploadPath(String publicPath) {
        path = publicPath + FilePathConstant.SQLPATH;
    }

    @Value("${bpm.approval.autoApproval}")
    private boolean autoApproval;
    private List<String> supportExcelType = Lists.newArrayList( "xls", "xlsx");

    /**
     * @param id
     * @return org.springblade.core.tool.api.R<com.dhcc.bpm.common.json.JSONObject>
     * @Description 详情
     * @Author daina
     * @Date 14:42 2020/2/25
     **/
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入product")
    @Log(title = "api发布表分页", businessType = BusinessType.SELECT)
    @ApiLog("api发布表分页")
    public R<JSONObject> detail(Long id) {

        productListVo detail = productService.selectById(id);
        List<String> api_ids = null;
        if (detail != null) {
            api_ids = productApiService.selectRelatedApi(detail.getId());
        }
        JSONObject json = new JSONObject();
        json.put("api_ids", api_ids);
        json.put("detail", detail);
        return R.data(json);
    }

    /**
     * @param product
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.api.entity.Product>>
     * @Description 分页 产品表
     * @Author daina
     * @Date 14:42 2020/2/25
     **/
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入product")
    @Log(title = "api发布表分页", businessType = BusinessType.SELECT)
    @ApiLog("api发布表分页")
    public R<IPage<ProductVO>> list(ProductVO product, Query query) {
//        IPage<Product> pages = productService.page(Condition.getPage(query), Condition.getQueryWrapper(product));
        IPage<ProductVO> pages = productService.selectProductPage(Condition.getPage(query), product);
        return R.data(pages);
    }


    @PostMapping("/download")
    public void download(ProductVO productVO, HttpServletResponse response) {
        int pagenum = 1;
        List<ProductVO> ApiVOlist = new ArrayList<>();
        while (true) {
            Query query = new Query();
            query.setCurrent(pagenum++);
            query.setSize(10);

            IPage<ProductVO> page = productService.selectProductPage(Condition.getPage(query), productVO);
            // 统计信息  (响应次数、响应成功率、响应时间)
            if (page.getRecords() != null && page.getRecords().size() > 0) {
                ApiVOlist.addAll(page.getRecords());
            } else {
                break;
            }
        }

        ExcelUtil<ProductVO> util = new ExcelUtil<ProductVO>(ProductVO.class);
        util.exportExcel(ApiVOlist, "API应用产品信息表", response);
    }


    /**
     * @param product
     * @param bladeUser
     * @return org.springblade.core.tool.api.R<java.util.List < com.dhcc.bpm.modules.api.entity.Product>>
     * @Description 下拉产品
     * @Author daina
     * @Date 14:43 2020/2/25
     **/
    @GetMapping("/select")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "下拉产品名称", notes = "传入product")
    @Log(title = "api发布表分页", businessType = BusinessType.SELECT)
    @ApiLog("api发布表分页")
    public R<List<Product>> select(Product product, BladeUser bladeUser) {
        QueryWrapper<Product> queryWrapper = Condition.getQueryWrapper(product);
        List<Product> list = productService.list((!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Product::getTenantId, bladeUser.getTenantId()) : queryWrapper);
        return R.data(list);
    }

    /**
     * @param product
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.api.vo.ProductVO>>
     * @Description 自定义分页 产品表
     * @Author daina
     * @Date 14:43 2020/2/25
     **/
    @GetMapping("/page")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入product")
    @Log(title = "api发布表分页", businessType = BusinessType.SELECT)
    @ApiLog("api发布表分页")
    public R<IPage<ProductVO>> page(ProductVO product, Query query) {
        IPage<ProductVO> pages;
        if (product.getApiId() != null) {
            //根据api的id查所有应用产品id
            List<ProductVO> list = productService.selectProductApiPage(product);
            List<String> peoIds = new ArrayList();
            if (list.size() > 0) {
                for (ProductVO productVO : list) {
                    peoIds.add(productVO.getId().toString());
                }
            }
            //去重
            List<String> productIdsList = new ArrayList<>(new TreeSet<>(peoIds));
            Long[] ids = new Long[productIdsList.size()];
            for (int i = 0; i < productIdsList.size(); i++) {
                ids[i] = Long.valueOf(productIdsList.get(i));
            }
            ProductVO product1 = new ProductVO();
            product1.setProductIds(ids);
            if (product1.getProductIds().length == 0) {
                R r = new R();
                r.setCode(200);
                r.setMsg("没有对应的关联应用产品");
                r.setData(null);
                return r;
            }
            pages = productService.selectProductPage(Condition.getPage(query), product1);
        } else if (product.getOpcSysId() != null) {
            //系统管理跳转统计时查询-------关联应用产品数据
            ProductVO productVO = new ProductVO();
            productVO.setOpcSysId(product.getOpcSysId());
            List<ProductVO> productList = productService.selectProductBySysId(productVO);
            if (productList.size() == 1 && null == productList.get(0)) {
                R r = new R();
                r.setCode(200);
                r.setMsg("没有对应的关联应用产品");
                r.setData(null);
                return r;
            }
            List<String> peoIds = new ArrayList();
            if (productList.size() > 0) {
                for (ProductVO product2 : productList) {
                    if (null != product2) {
                        peoIds.add(product2.getId().toString());
                    }
                }
            }
            Long[] ids = new Long[peoIds.size()];
            for (int i = 0; i < peoIds.size(); i++) {
                ids[i] = Long.valueOf(peoIds.get(i));
            }
            ProductVO product1 = new ProductVO();
            product1.setProductIds(ids);//找到对应的应用产品id
            if (product1.getProductIds().length == 0) {
                R r = new R();
                r.setCode(200);
                r.setMsg("没有对应的关联应用产品");
                r.setData(null);
                return r;
            }
            pages = productService.selectProductPage(Condition.getPage(query), product1);
        } else if (product.getBaseProductId() != null) {
            //基础产品查找应用id
            ProductVO productVO = new ProductVO();
            productVO.setBaseProductId(product.getBaseProductId());
            List<ProductVO> productList = productService.selectProductByBaseProduct(productVO);
            if (productList.size() == 1 && null == productList.get(0)) {
                R r = new R();
                r.setCode(200);
                r.setMsg("没有对应的关联应用产品");
                r.setData(null);
                return r;
            }
            List<String> peoIds = new ArrayList();
            if (productList.size() > 0) {
                for (ProductVO product2 : productList) {
                    if (null != product2) {
                        peoIds.add(product2.getId().toString());
                    }
                }
            }
            Long[] ids = new Long[peoIds.size()];
            for (int i = 0; i < peoIds.size(); i++) {
                ids[i] = Long.valueOf(peoIds.get(i));
            }
            ProductVO product1 = new ProductVO();
            product1.setProductIds(ids);//找到对应的应用产品id
            if (product1.getProductIds().length == 0) {
                R r = new R();
                r.setCode(200);
                r.setMsg("没有对应的关联应用产品");
                r.setData(null);
                return r;
            }
            pages = productService.selectProductPage(Condition.getPage(query), product1);
        } else {

            pages = productService.selectProductPage(Condition.getPage(query), product);
        }


        if (pages.getRecords() != null && pages.getRecords().size() > 0) {

            for (ProductVO productVO : pages.getRecords()) {
                // 求成功率
                String successRateStr = "0.00";
                // 平均响应时间
                double avgResTime = 0.00;
                Long num = 0L;
                //----------------------应用产品对应的api----------------------
                List<Long> apiIds = apiService.getProdApiIdsByProductId(productVO.getId());

                ApiVO apiVO = new ApiVO();
                if (CollectionUtils.isEmpty(apiIds)) {
                    //没有对应的apiId 不用去计算了
                    productVO.setNum(num);
                    productVO.setSuccessRate("0.00%");
                    productVO.setResponseTime(Double.valueOf(0.00));
                    continue;
                }
                apiVO.setApiIds(apiIds);
                List<ApiVO> apiVOList = apiService.selectApiList(apiVO);
                // 统计信息  (响应次数、响应成功率、响应时间)
                for (ApiVO apiVO2 : apiVOList) {
                    AppApiViewVo appApiViewVo = new AppApiViewVo();
                    appApiViewVo.setApiId(apiVO2.getApiCode());
                    appApiViewVo.setEnv("0"); // 环境标志  0-生产环境
                    AppApiViewVo apiCountData = gatewayLogDayService.apiCount(appApiViewVo);
                    if (apiCountData != null) {
                        DecimalFormat df = new DecimalFormat("0.00");//格式化小数

                        double successRate = 0.00;
                        if (apiCountData.getRequestNum() != 0) {
                            successRate = (double) apiCountData.getSuccessNum() / apiCountData.getRequestNum() * 100;

                            successRateStr = FormatUtils.doubleFormat(Double.valueOf(successRateStr) + successRate);
                        }


                        if (apiCountData.getLineNum() != 0) {
                            double temp = Double.valueOf(df.format(apiCountData.getResponseTime() / apiCountData.getLineNum()));
                            avgResTime = Double.valueOf(df.format(avgResTime + temp));
                        }
                        num += apiCountData.getRequestNum();
                    }
                }
                productVO.setNum(num);
                DecimalFormat df = new DecimalFormat("0.00");//格式化小数
                if (successRateStr.equals("0.00")) {
                    productVO.setSuccessRate("0.00%");
                } else {
                    double SuccessRate = Double.valueOf(successRateStr) / apiVOList.size();
                    productVO.setSuccessRate(Double.valueOf(df.format(SuccessRate)) + "%");
                }

                if (avgResTime == 0.0) {
                    productVO.setResponseTime(Double.valueOf(0.00));
                } else {
                    productVO.setResponseTime(Double.valueOf(df.format(avgResTime / apiVOList.size())));
                }

            }
        }

        // 统计信息  (响应次数、响应成功率、响应时间)
//        if(pages.getRecords() != null && pages.getRecords().size() > 0) {
//            for(ProductVO productVO: pages.getRecords()) {
//                ProductRankVo productRankVo = new ProductRankVo();
//                productRankVo.setProductId(productVO.getId().toString());
//                // 环境标志  0-生产环境
//                String env = "0";
//                productRankVo.setEnv(env);
//
//                List<ProductRankVo> rankList = gatewayLogDayService.countProductByDate(productRankVo);
//                if( rankList != null && rankList.size() > 0 && rankList.get(0) != null && rankList.get(0).getNum() != null) {
//                    ProductRankVo rankVo = rankList.get(0);
//                    DecimalFormat df = new DecimalFormat("0.00");//格式化小数
//                    // 求成功率
//                    String successRateStr = "0.00%";
//                    double successRate = 0;
//                    if(rankVo.getNum() != 0  ) {
//                        successRate = (double) rankVo.getSuccessNum()/rankVo.getNum() * 100;//返回的是String类型
//                        successRateStr = FormatUtils.doubleFormat(successRate) + "%";
//                    }
//
//                    // 平均响应时间
//                    double avgResTime = 0.00;
//                    if(rankVo.getLineNum() != 0) {
//                        avgResTime = Double.valueOf( df.format(rankVo.getResponseTime() / rankVo.getLineNum()) );
//                    }
//
//                    productVO.setNum(rankVo.getNum());
//                    productVO.setSuccessNum(rankVo.getSuccessNum());
//                    productVO.setSuccessRate(successRateStr );
//                    productVO.setResponseTime(avgResTime);
//                }
//            }
//        }
        return R.data(pages);
    }

    /**
     * @param product
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.api.vo.ProductVO>>
     * @Description 自定义分页 应用限流-产品列表
     * @Author daina
     * @Date 14:43 2020/2/25
     **/
    @GetMapping("/listAppProductPage")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入product")
    @Log(title = "api发布表分页", businessType = BusinessType.SELECT)
    @ApiLog("api发布表分页")
    public R<IPage<ProductVO>> listAppProductPage(ProductVO product, Query query) {
        IPage<ProductVO> pages = productService.listAppProductPage(Condition.getPage(query), product);
        return R.data(pages);
    }

    /**
     * @param product
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.api.vo.ProductVO>>
     * @Description 查询已发布的产品
     * @Author sjm
     * @Date 15:16 2020/3/21 0021
     **/
    @GetMapping("/fetchListRelease")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入product")
    @Log(title = "api发布表分页", businessType = BusinessType.SELECT)
    @ApiLog("api发布表分页")
    public R<IPage<ProductVO>> fetchListRelease(ProductVO product, Query query) {
        IPage<ProductVO> pages = productService.fetchListRelease(Condition.getPage(query), product);
        return R.data(pages);
    }

    /**
     * @param product
     * @return org.springblade.core.tool.api.R
     * @Description 新增 产品表
     * @Author daina
     * @Date 14:43 2020/2/25
     **/
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "新增", notes = "传入product")
    @Log(title = "新增产品", businessType = BusinessType.INSERT)
    @ApiLog("api发布表分页")
    public R save(@Valid @RequestBody Product product) {
        return R.status(productService.save(product));
    }

    @ApiLog("导入excel")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "导入excel", notes = "sysNum")
    @Log(title = "导入excel", businessType = BusinessType.SELECT)
    @PostMapping("importexcel")
    public R importexcel(Plupload plupload, HttpServletRequest request) {
        String name = null;
        Upload upload = new Upload();
        upload.setRequest(request);
        Upload uploadEntity = pluploadService.getFile(upload);
        MultipartFile file = uploadEntity.getMultipartFile();
        name = file.getOriginalFilename();
        String fileType = name.substring(name.lastIndexOf(".") + 1);
        if(!supportExcelType.contains(fileType)){
            return R.fail("请上传excel类型文档！");
        }
        uploadEntity.setName(name);
        //本地上传
        String id = pluploadService.fileLocalUpload(plupload, upload, request).toString();
        Plupload newupload = pluploadService.selectById(Long.parseLong(id));
        try (InputStream inputStream = new FileInputStream(new File(path + "/" + newupload.getFileRealname()))) {
            ExcelUtil<Product> excelUtil = new ExcelUtil<Product>(Product.class);
            List<Product> list = excelUtil.importExcel("API应用产品信息表", inputStream);
            for (Product sys : list) {
                try {
                    productService.save(sys);
                } catch (Exception e) {
                    log.error("数据库异常：{}", e);
                    if (e.getMessage().contains("for key 'sys_name_idx'") || e.getMessage().contains("ORA-00001")) {
                        continue;
                    } else {
                        return R.fail(500, "数据库异常");
                    }
                } finally {

                }
            }
            pluploadService.fileDelete(Long.parseLong(id));
        } catch (FileNotFoundException e) {
            log.error("异常信息:{}", e);
        } catch (Exception e) {
            log.error("异常信息:{}", e);
        }
        return R.success("导入成功");
    }

    /**
     * @param product
     * @return org.springblade.core.tool.api.R
     * @Description 修改 产品表
     * @Author daina
     * @Date 14:43 2020/2/25
     **/
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入product")
    @Log(title = "修改产品", businessType = BusinessType.UPDATE)
    @ApiLog("api发布表分页")
    @Transactional(rollbackFor = Exception.class)
    public R update(@Valid @RequestBody Product product) {
        //修改低版本product为已升级，不推荐
        if (product.getId() != null && product.getIsUpgrade() == 2) {
            Product prod = new Product();
            prod.setId(product.getId());
            // IsRecommend 是否推荐 1：推荐  2：不推荐
            prod.setIsRecommend(2);
            // IsUpgrade 2：未升级 3：已升级
            prod.setIsUpgrade(2L);
            productService.updateById(prod);
            //新数据
            product.setId(null);
            product.setIsUpgrade(3L);
            product.setIsRecommend(1);
        }
        // 提交
        if (null == product.getId() || product.getId() <= 0) {
            Long id = System.currentTimeMillis();
            product.setId(id);
            String code = serialNumberService.generateSerialNumberByModelCode("opc_product");
            product.setProductCode(code);
            // status ；9 ：未发布
            product.setStatus(9);
            product.setReleaseTime(DateUtils.asDate(LocalDateTime.now()));
        }

        boolean flag = productService.save(product);

        Product productInfo = productService.getById(product.getId());
        if (flag) {
            // 产品下线发送邮件通知
            List<App> appLists = appService.listByProductId(productInfo.getId());
            for (App app : appLists) {
                // 发送邮件通知
                String mailTitle = appEmailConfig.getTitle() + productInfo.getProductName() + "产品升级通知";
                String msg = "尊敬的用户，您好！\r\n" + "您订阅的产品：[" + productInfo.getProductName() + " ]已升级，详情请登录开放门户查看！";
                if (app.getPrpEmail() != null) {
                    emailUtils.sendEmail(mailTitle, app.getPrpEmail(), mailTitle, msg);
                }
            }
        }
        return R.status(flag);
    }

    /**
     * @param product
     * @return org.springblade.core.tool.api.R
     * @Description 修改 产品表
     * @Author daina
     * @Date 14:43 2020/2/25
     **/
    @PostMapping("/changeStatus")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入product")
    @Log(title = "修改产品", businessType = BusinessType.UPDATE)
    @ApiLog("api发布表分页")
    public R changeStatus(@Valid @RequestBody Product product) {
        CostRuleVO costRule = costRuleService.getByProductId(product.getId());
        if (null != costRule) {
            costRule.setStatus(product.getProductStatus());
            costRuleService.updateById(costRule);
        }
        return R.status(productService.updateById(product));
    }

    /**
     * @param json
     * @return org.springblade.core.tool.api.R
     * @Description 新增或修改 产品表
     * @Author daina
     * @Date 14:44 2020/2/25
     **/
    @PostMapping("/submit")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改产品", notes = "传入product")
    @Log(title = "新增或修改产品", businessType = BusinessType.INSERT)
    @ApiLog("新增或修改产品")
    @Transactional(rollbackFor = Exception.class)
    public R submit(@Valid @RequestBody com.alibaba.fastjson.JSONObject json) throws Exception {
        try {
            com.alibaba.fastjson.JSONObject pro = json.getJSONObject("values");
            Product product = json.getJSONObject("values").toJavaObject(Product.class);
//            Product product = new Product();
//            product.setProductName(pro.getStr("productName"));
//            product.setProductEname(pro.getStr("productEname"));
//            product.setProductCode(pro.getStr("productCode"));
//            product.setProductVersion(pro.getStr("productVersion"));
//            product.setPrivilegeLevel(pro.getInt("privilegeLevel"));
//            product.setIsCost(pro.getInt("isCost"));
//            product.setIsRecommend(pro.getInt("isRecommend"));
//            product.setRecommendDescribe(pro.getStr("recommendDescribe"));
//            product.setPid(pro.getLong("pid"));
//            Instant instant = new Date().toInstant();
//            ZoneId zoneId = ZoneId.systemDefault();
//            product.setReleaseTime(DateUtils.asDate(LocalDateTime.now()));
//            product.setOpcSysId(pro.getLong("opcSysId"));
//            product.setDescribe(pro.getStr("describe"));
//            JSONObject.JSONArray targetKeys = json.getArr("targetKeys");
            /**
             * 判断产品中是否包含id ，如果包含则说明 是修改， 不包含则是新增
             */

            if (null == product.getId() || product.getId() <= 0) {
//            if (null == pro.getLong("id") || pro.getLong("id") <= 0) {
                Long id = System.currentTimeMillis();
                product.setId(id);
//                String code = serialNumberService.generateSerialNumberByModelCode("opc_product");
//                product.setProductCode(code);
                // status 9:未发布
                product.setStatus(9);
                product.setReleaseTime(DateUtils.asDate(LocalDateTime.now()));
//            for (int i = 0; i < targetKeys.size(); i++) {
//                ProductApi productApi = new ProductApi();
//                productApi.setApiId(Long.parseLong(targetKeys.get(i) + ""));
//                productApi.setProductId(id);
//                productApi.setStatus(9);
//                productApiService.saveOrUpdate(productApi);
//            }
                return R.status(productService.save(product));
            } else {
//                product.setId(pro.getLong("id"));
                productApiService.updateDeleteRelate(product.getId());
//            for (int i = 0; i < targetKeys.size(); i++) {
//                ProductApi productApi = new ProductApi();
//                productApi.setApiId(Long.parseLong(targetKeys.get(i) + ""));
//                productApi.setProductId(pro.getLong("id"));
//                productApi.setStatus(9);
//                productApiService.saveOrUpdate(productApi);
//            }
                return R.status(productService.saveOrUpdate(product));
            }
        } catch (Exception e) {
            log.error("数据库异常:{}", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            if (e.getMessage().contains("for key 'product_name_idx'") || e.getMessage().contains("ORA-00001")) {
                return R.fail(500, "该产品已存在");
            }
            return R.fail(500, "数据库异常");
        } finally {

        }
    }


    /**
     * @param ids
     * @return org.springblade.core.tool.api.R
     * @Description 删除 产品表
     * @Author daina
     * @Date 14:44 2020/2/25
     **/
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "删除产品信息", notes = "传入ids")
    @Log(title = "删除产品信息", businessType = BusinessType.DELETE)
    @ApiLog("删除产品信息")
    @Transactional(rollbackFor = Exception.class)
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        boolean bool = true;
        //删除对应的工作流
        String[] arrayIds = ids.split(",");
        for (String id : arrayIds) {
            iWorkFlowService.deleteRelated("a", id);//产品发布
            iWorkFlowService.deleteRelated("z", id);//产品下线
        }
        List<Long> productIds = Func.toLongList(ids);
        for (int i = 0; i < productIds.size(); i++) {
            List<OpcAppApiVo> appApiVos = productService.selectAppApi(productIds.get(i));
            if (appApiVos.size() > 0) {
                //删除时判断该应用产品是否有渠道在使用，如果有渠道在使用则提示不能删除 OpcAppApi
                bool = false;
                break;
            }
            // 同时删除产品api关联表
            productIds.forEach(productId -> {
                //// opc_doc_directory
                DocDirectory docDirectory = new DocDirectory();
                productListVo productListVo = productService.selectById(productId);
                docDirectory.setDocCode(productListVo.getProductCode());
                DocDirectory detail = docDirectoryService.getOne(Condition.getQueryWrapper(docDirectory));
                if (detail != null) {
                    List<Long> docids = new LinkedList<>();
                    docids.add(detail.getId());
                    docDirectoryService.deleteLogic(docids);
                }
                productService.removeById(productId);
                //opc_product_api
                List<ProductApi> productApiLists = productApiService.productApiList(productId);
                if (productApiLists.size() > 0) {
                    for (ProductApi pro : productApiLists) {
                        productApiService.removeById(pro.getId());
                    }
                }
                // opc_app_api
                List<AppApi> appApiLists = appApiService.selectByProductId(productId);
                if (appApiLists.size() > 0) {
                    for (AppApi appApi : appApiLists) {
                        appApiService.removeById(appApi.getId());
                    }
                }
            });
        }
        //return R.status(bool);
        return bool ? success("操作成功") : fail("有渠道在使用，不能删除");
    }

    /**
     * @param json
     * @return org.springblade.core.tool.api.R
     * @Description 更新产品发布状态
     * @Author daina
     * @Date 14:44 2020/2/25
     **/
    @PostMapping("/approval")
    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "更新产品发布状态", notes = "api id 的数组 和产品Id")
    @Log(title = "更新产品发布状态", businessType = BusinessType.REFRESH)
    @ApiLog("更新产品发布状态")
    //发布按钮状态控制修改  修改时间20200922 11:14:11
    @Transactional(rollbackFor = Exception.class)
    public R approval(@Valid @RequestBody JSONObject json, BladeUser bladeUser) {
        boolean isAdmin = false;
        //判断用户是不是 管理员，是的话 直接审批通过
        Role role = roleService.getById(bladeUser.getRoleId());
        if ("administrator".equals(role.getRoleAlias())) {
            //是管理员
            isAdmin = true;
        }

        JSONObject.JSONArray ids = json.getObj("wfParm").getArr("selectedRowKeys");
        String appId = json.getStr("appId");
        String product_id = appId.substring(1);
        R r = new R();

        /**
         *先开始更新数据库状态，因为数据库可以进行回滚
         */
        Product product = productService.getById(Long.parseLong(product_id));
        /**
         * 查询到的产品数据不能为空，且状态
         */
        //发布按钮状态控制修改  修改时间20200922 11:14:11
        if (product == null) {
            r.setSuccess(false);
            r.setMsg("产品信息查询失败");
            return r;

        } else {
            product.setStatus(0);
            //回滚数据库
            if (!productService.updateById(product)) {
                r.setSuccess(false);
                r.setMsg("产品状态更新失败");
                return r;
            }
        }
        /**
         * 让后更新api的发布状态
         */
        ProductApi productApi = new ProductApi();
        productApi.setProductId(Long.parseLong(product_id));
        for (int i = 0; i < ids.size(); i++) {

            com.dhcc.bpm.modules.api.entity.Api api = apiService.getById(Long.parseLong(ids.get(i) + ""));
            /**
             * 首先更新api关联发布状态,判断是否已经关联过,关联过则不更新
             */
//			if(api.getStatus()!=0){
//				api.setStatus(0);
//				if(!apiService.updateById(api)){
//                    /**
//                     * 数据库回滚状态
//                     */
//                    r.setSuccess(false);
//                    r.setMsg("Api状态更新失败");
//                    return r;
//                }
//			}
            /**
             * 更新关联表发布状态
             */
            productApi.setApiId(Long.parseLong(ids.get(i) + ""));
            // status 0:发布审核中
            productApi.setStatus(0);
            productApiService.updateStatus(productApi);

        }
        try {
            ProcessStartDto processStartDto = new ProcessStartDto();
            processStartDto.setAppId(appId);
            processStartDto.setWfParm(json.getObj("wfParm"));
            processStartDto.setUserId(json.getStr("userId"));
            processStartDto.setProcessKey(json.getStr("processKey"));
            JSONObject jsonObject = iWorkFlowService.start(processStartDto);
            System.out.println(jsonObject);
            if (jsonObject.getInt("code") == 200) {
                if (autoApproval && isAdmin) {
                    //直接审批通过
                    JSONObject jsonObject2 = (JSONObject) jsonObject.get("data");
                    String EXECUTION_ID_ = jsonObject2.getStr("instanceId");//EXECUTION_ID_字段
                    TaskDto taskDto = new TaskDto();
                    taskDto.setProcessKeys(EXECUTION_ID_);
                    taskDto = iWorkFlowService.findBytask(taskDto);
                    TaskCommitDto taskCommitDto = new TaskCommitDto();
                    taskCommitDto.setApiIds(new ArrayList<>());
                    taskCommitDto.setOpinionType("1");
                    taskCommitDto.setTaskId(taskDto.getId());
                    taskCommitDto.setUserId(bladeUser.getUserId().toString());
                    JSONObject json2 = iWorkFlowService.commit(taskCommitDto);
                    if (json2 != null && json2.getInt("code") == 200) {
                        if ("chnl".equals(json2.getStr("type"))) {
                            iWorkFlowService.refreshApp(json2.getStr("id"));
                        }
                        if ("api".equals(json2.getStr("type"))) {
                            iWorkFlowService.refreshApi(json2.getStr("id"));
                        }

                    } else {
                        r.setSuccess(false);
                        r.setMsg(jsonObject.get("msg") == null ? "" : jsonObject.get("msg").toString());
                        return r;
                    }
                }
                r.setSuccess(true);
                r.setCode(jsonObject.getInt("code"));
                if (autoApproval && isAdmin) {
                    r.setMsg("发布成功,并自动审批");
                } else {
                    r.setMsg("发布成功");
                }
                return r;
            } else {
                //都要对数据库进行回滚
                r.setSuccess(false);
                r.setCode(jsonObject.getInt("code"));
                r.setMsg(jsonObject.getStr("msg"));
                return r;
            }
        } catch (Exception e) {
            log.info("数据库异常：{}", e.getMessage());            //数据库回滚
            //发布按钮状态控制修改  修改时间20200922 11:14:11
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            r.setSuccess(false);
            r.setMsg("应用产品发布提交失败");
            return r;
        } finally {

        }

    }

    /**
     * @param id
     * @return org.springblade.core.tool.api.R<com.dhcc.bpm.common.json.JSONObject>
     * @Description 查询产品关联API详情
     * @Author daina
     * @Date 14:44 2020/2/25
     **/
    @GetMapping("/listRelatedApiDetail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "查询产品关联API详情", notes = "传入product")
    @Log(title = "查询产品关联API详情", businessType = BusinessType.SELECT)
    @ApiLog("查询产品关联API详情")
    public R<JSONObject> listRelatedApiDetail(Long id) {

        //Product product = productService.getById(id);
        productListVo product = productService.selectById(id);
        List<ApiBO> relatedApis = null;
        if (product != null) {
            relatedApis = productApiService.listRelatedApiDetail(product.getId());
        }

        JSONObject json = new JSONObject();
        json.put("product", product);
        json.put("detail", relatedApis);
        return R.data(json);
    }

    /**
     * @param reqJson
     * @return org.springblade.core.tool.api.R<com.dhcc.bpm.common.json.JSONObject>
     * @Description 维护产品API
     * @Author daina
     * @Date 14:44 2020/2/25
     **/
    @PostMapping("/maintain")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改productApi", notes = "传入product")
    @Log(title = "新增或修改productApi", businessType = BusinessType.OTHER)
    @ApiLog("新增或修改productApi")
    public R<JSONObject> maintain(@Valid @RequestBody JSONObject reqJson) {
//        return productApiService.maintainProductApi(reqJson);
        R r = new R();
        try {
            String opt = reqJson.getStr("opt");
            Long productId = reqJson.getLong("productId");
            JSONObject.JSONArray apiIds = reqJson.getArr("apiIds");
            for (int i = 0; i < apiIds.size(); i++) {
                ProductApi productApi = new ProductApi();
                productApi.setApiId(Long.parseLong(apiIds.get(i) + ""));
                productApi.setProductId(productId);
                // 9：未发布
                productApi.setStatus(9);
                productApi.setCreateTime(DateUtil.now());
                productApi.setIsDeleted(0);
                productApi.setExpSeq(stringRedisTemplate.opsForValue().get("expSeq"));
                // A新增 D删除`
                int number;
                if ("A".equals(opt)) {
                    productApiService.saveOrUpdate(productApi);
                } else if ("D".equals(opt)) {
//					productApi.setStatus(6);
                    productApiService.delete(productApi);
                }
            }
            r.setSuccess(true);
            r.setMsg("更新成功");
            return r;
        } catch (Exception e) {
            log.info("数据库异常：{}", e.getMessage());            //数据库回滚
            r.setSuccess(false);
            r.setMsg(e.getMessage());
            return r;
        } finally {

        }
    }


    /**
     * @param processStartDto
     * @return org.springblade.core.tool.api.R
     * @Description 产品下线申请
     * @Author daina
     * @Date 14:44 2020/2/25
     **/
    @PostMapping("/offShelveApply")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "产品下线申请", notes = "传入ProcessStartDto")
    @Log(title = "产品下线申请", businessType = BusinessType.SELECT)
    @ApiLog("产品下线申请")
    @Transactional(rollbackFor = Exception.class)
    public R offShelveApply(@RequestBody ProcessStartDto processStartDto, BladeUser bladeUser) {
        R r = new R();
        boolean isAdmin = false;
        //判断用户是不是 管理员，是的话 直接审批通过
        Role role = roleService.getById(bladeUser.getRoleId());
        if ("administrator".equals(role.getRoleAlias())) {
            //是管理员
            isAdmin = true;
        }
        // 调用发布流程接口
        JSONObject resJson = null;
        try {
            resJson = iWorkFlowService.start(processStartDto);
        } catch (Exception e) {
            r.setSuccess(false);
            r.setMsg("下线申请提交失败");
            return r;
        }
        // 发布流程成功
        if (resJson != null && resJson.getInt("code") == 200) {
            String appId = processStartDto.getAppId();
            Long productId = Long.parseLong(appId.substring(1, appId.length()));
            // 更新 opc_product
            Product product = new Product();
            product.setId(productId);
            // status 5:下线待审批
            product.setStatus(5);
            boolean proUpdated = productService.updateById(product);
            // 更新 opc_product_api
            ProductApi productApi = new ProductApi();
            productApi.setProductId(productId);

            // status 5:下线待审批
            productApi.setStatus(5);
            int apiUpdated = productApiService.updateApiStatus(productApi);
            if (autoApproval && isAdmin) {
                //直接审批通过
                JSONObject jsonObject2 = (JSONObject) resJson.get("data");
                String EXECUTION_ID_ = jsonObject2.getStr("instanceId");//EXECUTION_ID_字段
                TaskDto taskDto = new TaskDto();
                taskDto.setProcessKeys(EXECUTION_ID_);
                taskDto = iWorkFlowService.findBytask(taskDto);
                TaskCommitDto taskCommitDto = new TaskCommitDto();
                taskCommitDto.setApiIds(new ArrayList<>());
                taskCommitDto.setOpinionType("1");
                taskCommitDto.setTaskId(taskDto.getId());
                taskCommitDto.setUserId(bladeUser.getUserId().toString());
                JSONObject json2 = iWorkFlowService.commit(taskCommitDto);
                if (json2 != null && json2.getInt("code") == 200) {
                    if ("chnl".equals(json2.getStr("type"))) {
                        iWorkFlowService.refreshApp(json2.getStr("id"));
                    }
                    if ("api".equals(json2.getStr("type"))) {
                        iWorkFlowService.refreshApi(json2.getStr("id"));
                    }

                } else {
                    r.setSuccess(false);
                    r.setMsg(resJson.get("msg") == null ? "" : resJson.get("msg").toString());
                    return r;
                }
            }

            if (proUpdated & apiUpdated != 0) {
                r.setSuccess(true);
                if (autoApproval && isAdmin) {
                    r.setMsg("下线申请提交成功,并自动审批");
                } else {
                    r.setMsg("下线申请提交成功");
                }
                return r;
            }
        } else {
            r.setSuccess(false);
            r.setMsg("下线申请提交失败");
            return r;
        }
        r.setSuccess(false);
        r.setMsg("下线申请提交失败");
        return r;
    }


    /**
     * @param
     * @return org.springblade.core.tool.api.R<com.dhcc.bpm.modules.gateway.entity.GatewayRoute>
     * @Description 刷新产品配置
     * @Date 2019/11/27 15:02
     **/
    @ApiLog("刷新产品配置")
    @PostMapping("/refreshProduct")
    @ApiOperationSupport(order = 8)
    @Log(title = "刷新产品配置", businessType = BusinessType.REFRESH)
    public R refreshProduct() {
        try {
            String message = redisMessageSender.format(ConfigType.APPSECRET.name(), "刷新产品公私钥配置");
            redisMessageSender.sendMessageToGateway(null, message);
            String msg = redisMessageSender.format(ConfigType.RATELIMET.name(), "刷新产品限流配置");
            redisMessageSender.sendMessageToGateway(null, msg);
            return R.status(true);
        } catch (Exception e) {
            log.error("刷新产品配置失败:{}", e);
            return R.status(false);
        }
    }


    /**
     * @param appId
     * @return org.springblade.core.tool.api.R
     * @Description 根据渠道ID查询产品
     * @Author sjm
     * @Date 15:26 2020/3/31 0031
     **/
    @ApiLog("查询产品名称")
    @GetMapping("/selectProdName")
    @ApiOperationSupport(order = 8)
    @Log(title = "查询产品名称", businessType = BusinessType.SELECT)
    public R selectProd(@ApiParam(value = "appId", required = true) @RequestParam Long appId) {
        List<Sys> list = sysService.selectSysById(appId);
        return R.data(list);
    }


    /**
     * @param productCode
     * @throws
     * @Description 编码判断是否重复
     * @Author wjh
     * @Date 2020年9月10日09:11:38
     **/
    @ApiLog("查询产品编码")
    @PostMapping("/selectByProductCode")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "查询产品编码", notes = "productCode")
    @Log(title = "查询产品编码", businessType = BusinessType.SELECT)
    public R selectByProductCode(@ApiParam(value = "产品编码", required = true) @RequestParam String productCode) {
        List<ProductVO> list = productService.selectByProductCode(productCode);
        if (list.size() > 0) {
            return R.data(false);
        }
        return R.data(true);
    }

    /**
     * @param
     * @return com.dhcc.bpm.common.json.JSONObject
     * @Description 产品名称查询
     * @Author daina
     * @Date 14:40 2020/2/25
     **/
    @GetMapping("/selectByProductName")
    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "产品名称查询", notes = "无参")
    @Log(title = "产品名称查询", businessType = BusinessType.SELECT)
    @ApiLog("产品名称查询")
    public JSONObject selectByProductName() {
        JSONObject object = new JSONObject();
        object.put("success", true);
        object.put("names", productService.selectByProductName());
        return object;
    }
}
